/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package uk.ac.cam.can.algorithm;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import uk.ac.cam.can.Data;
import uk.ac.cam.can.evaluation.Evaluation;

/**
 *
 * @author thomas
 */
public class CutingKAnon {
    private Data data;
    protected int k;
    protected int ct;
    protected double d;
    private long executionTime;
    private List<List<String[]>> parts = new ArrayList<List<String[]>>();
    
    public CutingKAnon(Data data, int k, int ct, double d){
        this.data=data;
        this.k=k;
        this.d=d;
        this.ct=ct;
    }
    
    public void findBest() throws Exception{
        long start = System.nanoTime();
        
        
        
        
        File f = new File("./tmp/"+k+"-cut-kanon.csv");
        f.delete();
        BufferedWriter buff = new BufferedWriter(new FileWriter("./tmp/"+k+"-cut-kanon.csv"));
        this.cutting();
        for(int i = 0; i < parts.size(); i++){
            Data tmp = dataFromPart(parts.get(i));
            callAnonymisation(tmp);
            
            for(String[] record : data.getRecords()){
                String line="";
                for(String a : record){
                    line+=a+data.getSeparator();
                }
                buff.write(line);
                buff.newLine();
            } 
            buff.flush();
        }
        buff.close();
        executionTime = ((System.nanoTime()-start)/1000000000);
    }
    
    private void cutting(){
        data.load();
        int rank[] = data.getAttributeOrderByCost();
        parts.add(data.getRecords());
        for(int p : rank){            
            List<List<String[]>> reject = new ArrayList<List<String[]>>();
            List<List<String[]>> accept = new ArrayList<List<String[]>>();
            if(data.getType(p)==Data.TYPE_QUASI_IDENTIFIER){
                
                
                for(List<String[]> part : parts){
                    Map<String, List<String[]>> groups = dividOn(p, part);
                    // is this division acceptable?
                    boolean isAcceptable=true;
                    for(List rs : groups.values()){
                        isAcceptable&=(rs.size()>=ct);
                    }
                    if(isAcceptable){
                        reject.add(part);                        
                        accept.addAll(groups.values());
                    }
                }
                parts.removeAll(reject);
                parts.addAll(accept);
            }
        }
    }
    
    public void printResult(){
        System.out.println("Cuting Anon Result");
        System.out.println("Number of parts "+parts.size());
        System.out.println("Anonymisation: "+executionTime+"s");
        data.load("./tmp/"+k+"-cut-kanon.csv");
        System.out.println("Quality : "+Evaluation.computeQuality(data));
        System.out.println("Risk : "+Evaluation.computeRisk(data));
    }
    
    public Map<String, List<String[]>> dividOn(int p, List<String[]> records){
        Map<String, List<String[]>> groups = new HashMap<String, List<String[]>>();
        if(data.getType(p)==Data.TYPE_QUASI_IDENTIFIER){
            for(String[] record : records){
                if(!groups.containsKey(record[p])){
                    groups.put(record[p], new ArrayList<String[]>());
                }
                groups.get(record[p]).add(record);
            }
        }
        return groups;
    }
    
    public Data dataFromPart(List<String[]> parts) throws Exception{
        data.listOfRecordToFile(parts, "./tmp/parts.txt");
        data.load("./tmp/parts.txt");
        return data;
    }

    protected void callAnonymisation(Data tmp) {
        KAnon ka = new KAnon(tmp, k, d);
        ka.findBest();
    }
}
